package com.example.util;

import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Calendar;
import java.util.UUID;

/**
 * 生成token及校验token相关方法
 */
public class JwtUtils {
    private static final String JWT_PAYLOAD_USE_KEY = "user";

    /**
     * 私钥加密token，由三部分组成：Header,Payload,Signature
     * Header:包含算法类型（如：{"alg":"RS256"})和Token类型（如：{"typ":"JWT"}）
     * Payload:存放业务数据（如用户ID，过期时间等）
     * Signature:对Header+Payload的SHA-256哈希值，用RSA私钥加密生成。
     */
    public static String generateToken(Object userInfo, PrivateKey privateKey, int expire) {
        //计算过期时间
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, expire);

        return Jwts.builder()
                .claim(JWT_PAYLOAD_USE_KEY, JSONUtil.toJsonStr(userInfo))
                .setId(new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes())))
                // 使用私钥进行加密
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .setExpiration(c.getTime())
                .compact();
    }

    /**
     * 验证签名并获取token中的用户信息
     * 验证签名的关键步骤如下：
     * 1.分离Token的Header，Payload和Signature
     * 2.使用publickey对签名部分（Signature）进行解密，得到原始的哈希值；
     * 3.重新计算Header + Payload的SHA-256哈希值，并与解密后的哈希值比对：
     *    如果一致，说明Token未被篡改且验证合法；
     *    如果不一致，说明Token被篡改，验证失败。
     */
    public static Object getInfoFromToken(String token, PublicKey publicKey, Class userType){
        //解析token
        Jws<Claims> claimsJws = Jwts
                .parser()
                // 使用公钥进行解密
                .setSigningKey(publicKey)
                .parseClaimsJws(token);

        //获取用户信息
        Claims body = claimsJws.getBody();
        String userInfoJson = body.get(JWT_PAYLOAD_USE_KEY).toString();
        return JSONUtil.toBean(userInfoJson,userType);
    }

}
